package com.finance.util.encrypt;

import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.annotation.adapters.HexBinaryAdapter;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * 加密组件
 * 
 * @author Administrator
 * 
 */
public abstract class EncryptUtil {
	static Logger logger = LoggerFactory.getLogger(EncryptUtil.class);

	public static final String KEY_SHA = "SHA";
	public static final String KEY_MD5 = "MD5";
	/**
	 * MAC算法可选以下多种算法
	 * 
	 * <pre>
	 * HmacMD5 
	 * HmacSHA1 
	 * HmacSHA256 
	 * HmacSHA384 
	 * HmacSHA512
	 * </pre>
	 */
	public static final String KEY_MAC = "HmacMD5";
	
	/**
	 * BASE64加密 
	 * BASE64 严格地说，属于编码格式，而非加密算法
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public static String encryptBASE64(byte[] key) throws Exception {
		return (new BASE64Encoder()).encodeBuffer(key).trim();
	}

	/**
	 * BASE64解密
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public static byte[] decryptBASE64(String key) throws Exception {
		return (new BASE64Decoder()).decodeBuffer(key);
	}
	
	/**
	 * MD5(Message Digest algorithm 5，信息摘要算法)
	 * 单向加密算法
	 * @param data
	 * @return
	 * @throws Exception
	 */
	public static byte[] encryptMD5(byte[] data) throws Exception {
		MessageDigest md5 = MessageDigest.getInstance(KEY_MD5);
		md5.update(data);
		return md5.digest();
	}

	/**
	 * MD5加密 
	 * 将消息摘要转成16进制字符串
	 * @param data
	 * @return
	 */
	public static String MD5Encode(String data){
		String resultString = null;
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");
			resultString = new HexBinaryAdapter().marshal(md.digest(resultString.getBytes()));
		} catch (Exception ex) {
		}
		return resultString;
		//or return new HexBinaryAdapter().marshal(encryptMD5(data.getBytes()));
	}

	public static String md5(String params) {
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");
			md.update(params.getBytes());
			byte[] b = md.digest();
			String result = "";
			String temp = "";

			for (int i = 0; i < 16; i++) {
				temp = Integer.toHexString(b[i] & 0xFF);
				if (temp.length() == 1) {
                    temp = "0" + temp;
                }
				result += temp;
			}
			return result;

		} catch (Exception e) {
			logger.error(e.getMessage(),e);
			return null;
		}
	}

	public static String md5(String params,String charset) {
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");
			md.update(params.getBytes());
			byte[] b = md.digest();
			String result = "";
			String temp = "";

			for (int i = 0; i < 16; i++) {
				temp = Integer.toHexString(b[i] & 0xFF);
				if (temp.length() == 1) {
                    temp = "0" + temp;
                }
				result += temp;
			}
			return result;

		} catch (Exception e) {
			logger.error(e.getMessage(),e);
			return null;
		}
	}

	/**
	 * MD5小32位加密获取摘要后再base64加密
	 */
	public static String md5Base64(String str,String charset){
		String digest = "";
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");
			md.update(str.getBytes(charset));
			digest = new String(Base64.encodeBase64(md.digest()), charset);
		} catch (NoSuchAlgorithmException e) {
			logger.error(e.getMessage(),e);
		} catch (UnsupportedEncodingException e) {
			logger.error(e.getMessage(),e);
		}
		return digest;
	}

	/**
	 * SHA(Secure Hash Algorithm，安全散列算法)
	 * 单向加密算法
	 * @param data
	 * @return
	 * @throws Exception
	 */
	public static byte[] encryptSHA(byte[] data) throws Exception {
		MessageDigest sha = MessageDigest.getInstance(KEY_SHA);
		sha.update(data);
		return sha.digest();
	}

	/**
	 * SHA1加密 
	 * @param data
	 * @return
	 * @throws Exception 
	 */
	public static String SHA1Encode(String data) throws Exception{
		 return new HexBinaryAdapter().marshal(encryptSHA(data.getBytes()));
	}

	/**
	 * HMAC(Hash Message Authentication Code，散列消息鉴别码)
	 * 单向加密算法
	 * @param data
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public static byte[] encryptHMAC(byte[] data, String key) throws Exception {
		SecretKey secretKey = new SecretKeySpec(decryptBASE64(key), KEY_MAC);
		Mac mac = Mac.getInstance(secretKey.getAlgorithm());
		mac.init(secretKey);
		return mac.doFinal(data);
	}
	
	/**
	 * 初始化HMAC密钥
	 * 
	 * @return
	 * @throws Exception
	 */
	public static String initMacKey() throws Exception {
		KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_MAC);
		SecretKey secretKey = keyGenerator.generateKey();
		return encryptBASE64(secretKey.getEncoded());
	}
}